package com.beidasoft.flip.webframe.core.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.lang.NonNull;

import com.beidasoft.flip.webframe.core.pojo.DO;
import com.beidasoft.flip.webframe.core.pojo.DTO;

/**
 * <p>JpaRepository接口的拓展，增加单个字段的查询方法</p>
 * <p>基础的Repository接口</p>
 * <P>泛型T指的是数据对象接口DataObj的子类</p>
 * @author 肖翔
 * @date 2019/12/03
 */
@NoRepositoryBean
public interface FlipJpaRepository<T extends DO, ID> extends JpaRepository<T, ID> {

    /**
     * <p>获取所有数据并封装到DTO的对象中，DTO对象与DO对象的字段映射关系，会根据fieldsmapping.yml文件中配置进行匹配</p>
     * @param pageable {@link Pageable}为自带分页和排序的对象
     * @param clazz 泛型S指的是传输对象接口DTO的子类的class
     * @param constructFields 对应需要实例含参构造器时的参数，如果没有就不填
     * @return 返回的DTO的对象集合封装到类型为{@link Page}的对象中
     */
    @SuppressWarnings("unchecked")
    <S extends DTO> Page<S> findAll2DTO(@NonNull Pageable pageable, @NonNull Class<S> clazz, Object... constructFields);

    /**
     * <p>获取所有数据并封装到类型为DTO的对象中，DTO对象与DO对象的字段映射关系，会根据fieldsmapping.yml文件中配置进行匹配</p>
     * @param clazz 泛型S指的是传输对象接口DTO的子类的class
     * @param constructFields 对应需要实例含参构造器时的参数，如果没有就不填
     * @return 将所有类型为DTO的结果封装到{@link List}对象中
     */
    @SuppressWarnings("unchecked")
    <S extends DTO> List<S> findAll2DTO(@NonNull Class<S> clazz, Object... constructFields);

    /**
     * <p>根据{@link Example}对象进行多字段的条件查询，获取所有数据并封装到类型为DTO的对象中，DTO对象与DO对象的字段映射关系，会根据fieldsmapping.yml文件中配置进行匹配</p>
     * @param example {@link Example}封装所有的查询条件
     * @param pageable pageable {@link Pageable}为自带分页和排序的对象
     * @param s 泛型S指的是传输对象接口DTO的子类的对象
     * @return 返回的DTO的对象集合封装到类型为{@link Page}的对象中
     */
    <S extends DTO> Page<S> find2DTO(@NonNull Example<T> example, @NonNull Pageable pageable, @NonNull S s);

    /**
     * <p>根据{@link Example}对象进行多字段的条件查询，获取所有数据并封装到类型为DTO的对象中，DTO对象与DO对象的字段映射关系，会根据fieldsmapping.yml文件中配置进行匹配</p>
     * @param example {@link Example}封装所有的查询条件
     * @param s 泛型S指的是传输对象接口DTO的子类的对象
     * @return 返回的DTO的对象集合封装到类型为{@link Page}的对象中
     */
    <S extends DTO> List<S> find2DTO(@NonNull Example<T> example, @NonNull S s);

    /**
     * <p>批量通过ids进行查询，获取到的数据并封装到DTO的对象中，DTO对象与DO对象的字段映射关系，会根据fieldsmapping.yml文件中配置进行匹配</p>
     * @param ids 接受多个id的集合
     * @param clazz 泛型S指的是传输对象接口DTO的子类的class
     * @param constructFields 对应需要实例含参构造器时的参数，如果没有就不填
     * @return 将所有类型为DTO的结果封装到{@link List}对象中
     */
    @SuppressWarnings("unchecked")
    <S extends DTO> List<S> findAll2DTOById(@NonNull Iterable<ID> ids, @NonNull Class<S> clazz,
        Object... constructFields);

    /**
     * <p>通过单个id进行查询，获取到的数据并封装到DTO的对象中，DTO对象与DO对象的字段映射关系，会根据fieldsmapping.yml文件中配置进行匹配</p>
     * @param id 为主键
     * @param s 泛型S指的是传输对象接口DTO的子类的对象
     * @return 将所有类型为DTO的结果封装到{@link Optional}对象中
     */
    <S extends DTO> Optional<S> find2DTOById(@NonNull ID id, @NonNull S s);

    /**
     * <p>单个DO对象新增或者更新，根据对象的主键进行判断，如果主键为空，则为新增，如果主键不为空，则先进行查询，再进行更新</P>
     * @param t 需要更新或者新增的对象
     * @return T 需要存储或者更新的对象本身
     */
    //    T addOrUpdate(@NonNull T t);

    /**
     * <p>多个DO对象进行新增或者更新，根据对象的主键进行判断，如果主键为空，则为新增，如果主键不为空，则先进行查询，再进行更新</P>
     * @param entities {@link Iterable}的实现类存储的对象，对象里包含了所有需要新增或者更新的对象
     * @return 用{@link List}返回了需要新增或者更新的对象
     */
    //    List<T> addOrUpdate(@NonNull Iterable<T> entities);

    /**
     * <p>执行查询SQL语句</p>
     * @param sql 需要执行的SQL语句
     * @param values 占位符顺序对应的值
     * @return 返回的对象包含执行语句得到返的结果
     */
    List<?> executeSqlQuery(String sql, Iterable<T> values);

    /**
     * <p>执行更新的SQL语句</p>
     * @param Hql 需要执行的SQL语句
     * @param values 占位符顺序对应的值
     * @return 返回的被更新对象的数量
     */
    int executeSqlUpdate(String sql, Iterable<T> values);
}
